package com.mew.auc.controller;

import com.alibaba.fastjson.JSON;
import com.mew.auc.Data.*;
import com.mew.auc.annotation.AseEncrypt;
import com.mew.auc.provide.RegisterFeignService;
import com.mew.auc.provide.SasFeignService;
import com.mew.auc.service.WebLoginService;
import com.mew.auc.util.SnowflakeUtil;
import com.mew.common.dc.db.LoginoutService;
import com.mew.common.dc.db.MaintenanceService;
import com.mew.common.dc.redis.AucRedisService;
import com.mew.common.enm.UserLoginType;
import com.mew.common.entity.sys.Maintenance;
import com.mew.common.exception.ResponseCode;
import com.mew.common.rest.bo.MewSession;
import com.mew.common.rest.login.ForcedOfflineRequest;
import com.mew.common.rest.sas.LoginSasRequest;
import com.zebra.common.OnlineType;
import com.zebra.common.concurrent.ZebraExecutorManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * @Date 2020/10/21 0021
 **/
@RestController
@Slf4j
public class LoginRegisterController {

    @Autowired
    WebLoginService loginService;

    @Autowired
    private LoginoutService loginoutService;

    @Autowired
    HttpServletRequest servletReq;

    @Autowired
    SnowflakeUtil snowflakeUtil;

    @Autowired
    private AucRedisService aucRedisService;

    @Autowired
    private RegisterFeignService registerFeignService;

    @Autowired
    private SasFeignService sasFeignService;

    @Autowired
    private MaintenanceService maintenanceService;


    @PostMapping(value = "/login/guest")
    @ResponseBody
    @AseEncrypt
    public String loginGuest(@RequestBody String param){
        LoginRsp rsp = new LoginRsp();
        try {
            LoginReq req = JSON.parseObject(param, LoginReq.class);
            String ip = getIP(servletReq);

            LoginData loginData = null;
            if (StringUtils.isEmpty(req.getGid())) {
                loginData = loginService.guestLoginByMac(req.getMac(), ip);
                if(loginData == null){
                    rsp.setStatus(ResponseCode.SysException.code());
                }
            }
            else {
                loginData = loginService.guestLogin(req.getMac(), req.getGid(), ip);
                if(loginData == null){
                    rsp.setStatus(ResponseCode.LoginFailed.code());
                }
            }

            checkLogin(loginData, rsp, req.getMac(), ip, req.getDevicesType());
            log.info("loginGuest param {} {}", param, rsp.toString());
            return JSON.toJSONString(rsp);
        }
        catch (Exception e) {
            log.error("loginGuest:", e);
            rsp.setStatus(ResponseCode.SysException.code());
            return JSON.toJSONString(rsp);
        }
    }

    @PostMapping(value = "/login/third")
    @ResponseBody
    @AseEncrypt
    public String loginThird(@RequestBody String param){
        LoginRsp rsp = new LoginRsp();
        try {
            ThirdLoginReq req = JSON.parseObject(param, ThirdLoginReq.class);
            String ip = getIP(servletReq);

            LoginData loginData = null;

            loginData = loginService.thirdLogin(req.getCode(), req.getType(), req.getNickname(),
                    req.getHeadImg(), ip, req.getMac());
            if(loginData == null){
                rsp.setStatus(ResponseCode.LoginFailed.code());
            }

            checkLogin(loginData, rsp, req.getMac(), ip, req.getDevicesType());
            log.info("loginThird param {} {}", param, rsp.toString());
            return JSON.toJSONString(rsp);
        }
        catch (Exception e) {
            log.error("loginThird:", e);
            rsp.setStatus(ResponseCode.SysException.code());
            return JSON.toJSONString(rsp);
        }
    }

    @PostMapping(value = "/login/account")
    @ResponseBody
    @AseEncrypt
    public String loginAccount(@RequestBody String param){
        LoginRsp rsp = new LoginRsp();
        try {
            AccountLoginReq req = JSON.parseObject(param, AccountLoginReq.class);
            String ip = getIP(servletReq);

            LoginData loginData = null;

            loginData = loginService.accountLogin(req.getAccount(), req.getPassword(), ip, req.getMac());
            if(loginData == null){
                rsp.setStatus(ResponseCode.LoginFailed.code());
            }
            if(loginData != null && loginData.getState() == 0)
            {
                rsp.setStatus(ResponseCode.UserState.code());
                loginData = null;
            }

            checkLogin(loginData, rsp, req.getMac(), ip, req.getDevicesType());
            log.info("loginAccount param {} {}", param, rsp.toString());
            return JSON.toJSONString(rsp);
        }
        catch (Exception e) {
            log.error("loginAccount:", e);
            rsp.setStatus(ResponseCode.SysException.code());
            return JSON.toJSONString(rsp);
        }
    }

    private void checkLogin(LoginData loginData, LoginRsp rsp, String mac, String ip, byte devicesType){
        if (loginData != null) {

            boolean canLogin = true;
            Maintenance maintenance = maintenanceService.queryMaintenanceInfo();

            if(maintenance != null && maintenance.getState() == 1 && !loginData.isInWhiteList())
            {
                canLogin = false;
            }

            if(canLogin) {

                MewSession session = doLogin(loginData.getId(), mac, ip, devicesType, loginData.isFirst());
                if (session != null) {
                    loginData.setToken(session.tk);
                    rsp.setStatus(ResponseCode.Success.code());
                    rsp.setData(loginData);
                }
            }
            else{
                rsp.setStatus(ResponseCode.InMaintenance.code());
                rsp.setMsg(maintenance.getMsg());
            }
        }
    }

    private MewSession doLogin(long userId, String mac, String ip, int devType, boolean isFirst){
        MewSession session = aucRedisService.getSession(userId);
        if (null != session && OnlineType.Online.value() == session.onl){
            registerFeignService.forcedOffline(ForcedOfflineRequest.builder()
                    .gatewaySid(session.gwsid)
                    .userId(session.uid)
                    .token(session.tk)
                    .build());
        }
        MewSession loginSession = loginoutService.login(session, userId, mac, ip, devType);
        log.info("---Login SESSION {}", loginSession);
        ZebraExecutorManager.getInstance().getDefaultExecutor().execute(() ->sasFeignService.loginSas(LoginSasRequest.builder().userId(userId).first(isFirst).loginType(UserLoginType.MAC.code()).build()));
        return loginSession;
    }

    private String getIP(HttpServletRequest request){
        String ip=request.getHeader("x-forwarded-for");
        if(ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ip)){
            ip=request.getHeader("Proxy-Client-IP");
        }
        if(ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ip)){
            ip=request.getHeader("WL-Proxy-Client-IP");
        }
        if(ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ip)){
            ip=request.getHeader("X-Real-IP");
        }
        if(ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ip)){
            ip=request.getRemoteAddr();
        }
        return ip;
    }

}
